﻿/*******************************************************************************
 * Level Master 2000
 * Copyright (C) 2010 Christian Herzog
 * For more information see http://code.google.com/p/levelmaster2000/
 *
 * This file is licensed under the terms of the MIT license, see
 * http://www.opensource.org/licenses/mit-license.php for further information.
 ******************************************************************************/

package com.levelmaster2000
{
   import com.levelmaster2000.SelectionChangedEvent;
   import com.pblabs.engine.core.*;
   import com.pblabs.engine.core.ITickedObject;
   import com.pblabs.engine.entity.*;
   import com.pblabs.engine.PBE;
   import com.pblabs.engine.resource.*;
   import com.pblabs.rendering2D.DisplayObjectRenderer;
   import com.pblabs.rendering2D.IMobileSpatialObject2D;
   import flash.display.*;
   import flash.events.*;
   import flash.geom.Point;
   
	public class TransformGizmo extends DisplayObjectRenderer implements ITickedObject
	{
		
        public function TransformGizmo() 
        {
            displayObject = new Sprite();
        }

        public function onTick(tickRate:Number):void
        {
        }		

        public override function onFrame(dt:Number):void
        {
			super.onFrame(dt);

            var tmpPosition:Point = new Point();
            var tmpRotation:Number = 0.0;

            alpha = 0;

            //Get current position of mouse in world coordinates:
            var currentMousePosition:Point = PBE.scene.transformScreenToWorld(
                new Point(PBE.mainStage.mouseX, PBE.mainStage.mouseY));
            
            
            for each( var target:DisplayObjectRenderer in targets )
            {
                if(target.owner == null)
                {
                    continue;
                }

                alpha = 255;
                
                //Translation Gizmo:
                var moveGFX:Graphics = (moveGizmo as Sprite).graphics;
                moveGFX.clear();
                {
                    moveGFX.beginFill(0x000000, 0.2);
                    moveGFX.lineStyle(1, 0xFF0000, 1);
                    moveGFX.drawRect(-width / 2,
                        -height / 2, 
                        width, 
                        height);
                    moveGFX.endFill();
                }
                moveGizmo.x = moveGizmo.y = 0;
                
                //Rotation Gizmo:
                var rotateGFX:Graphics = (rotateGizmo as Sprite).graphics;
                rotateGFX.clear();
                {
                    var rotateSize:int = 10;
                    var rotateGizmoOffset:Point = new Point(-40,0);
                    rotateGFX.beginFill(0x000000, 0.1);
                    rotateGFX.lineStyle(1, 0x00FF00, 1);
                    rotateGFX.drawRect(-rotateSize / 2,
                        -rotateSize / 2, 
                        rotateSize, 
                        rotateSize);
                    rotateGFX.endFill();
                }
                rotateGizmo.x = rotateGizmoOffset.x;
                rotateGizmo.y = rotateGizmoOffset.y;
            

                                //Rotation Gizmo:
                var scaleGFX:Graphics = (scaleGizmo as Sprite).graphics;
                scaleGFX.clear();
                {
                    var scaleSize:int = 10;
                    var scaleGizmoOffset:Point = new Point(40,-30);
                    scaleGFX.beginFill(0x000000, 0.1);
                    scaleGFX.lineStyle(1, 0x0000FF, 1);
                    scaleGFX.drawRect(-scaleSize / 2,
                        -scaleSize / 2, 
                        scaleSize, 
                        scaleSize);
                    scaleGFX.endFill();
                }
                scaleGizmo.x = scaleGizmoOffset.x;
                scaleGizmo.y = scaleGizmoOffset.y;

                
                //Note: if you want offsetted rotation, you need to modify it in the drawRect code 
            //(e.g. rotateGizmoOffset.x - rotate.Size/2)...
            
                alpha = 1.0;
                
                //Check if entity has a IMobileSpatialObject2D component:
                var comp:IMobileSpatialObject2D = 
                    target.owner.lookupComponentByType(IMobileSpatialObject2D) as IMobileSpatialObject2D;

                //Calculate the offset position;
                var offsetPos:Point = currentMousePosition.subtract(lastMousePos);

                //TODO: what is this good for again?
                //Check if a positionProperty is used:
                var usesPositionProperty:Boolean = false;
                if( target.positionProperty != null )
                {
                    usesPositionProperty = target.positionProperty.property == "" ? false : true;
                }

                var usesRotationProperty:Boolean = false;
                if( target.rotationProperty != null )
                {
                    usesRotationProperty = target.rotationProperty.property == "" ? false : true;
                }

                if(isTranslating)
                {
                    //If IMobileSpatialObject2D and positionProperty is used:
                    if(comp != null && usesPositionProperty)
                    {           
                        comp.position = new Point(comp.position.x + offsetPos.x, 
                            comp.position.y + offsetPos.y);
                
                        position = comp.position;                        
                    }
                    //Else, use DisplayObjectRenderer settings, as probably no Spatial component:
                    else
                    {
                        target.position = new Point(target.position.x + offsetPos.x, 
                            target.position.y + offsetPos.y);
                        
                        position = target.position;
                    }
                }
                else if(isRotating)
                {
                    //If IMobileSpatialObject2D:
                    if(comp != null && usesRotationProperty)
                    {         
                        comp.rotation += offsetPos.x;
                        rotation = comp.rotation;                        
                    }
                    //Else, use DisplayObjectRenderer settings, as probably no Spatial component:
                    else
                    {
                        target.rotation += offsetPos.x;
                        rotation = target.rotation;                        
                    }
                }
                else if(isScaling)
                {
                    //TODO: Due to hacking, currently only uniform scaling is supported.
                    //To support non uniform, just use offsetPos.y ...
                    //If IMobileSpatialObject2D and scaleProperty is used:
                    if(comp != null /*&& usesPositionProperty*/)
                    {           
                        comp.size = new Point(comp.size.x + offsetPos.x, 
                            comp.size.y + offsetPos.x);
                
                        //position = comp.size;                        
                    }
                    //Else, use DisplayObjectRenderer settings, as probably no Spatial component:
                    else
                    {
                        target.size = new Point(target.size.x + offsetPos.x, 
                            target.size.y + offsetPos.x);
                        
                        //position = target.position;
                    }
                }                
                else
                {
                    //Updates the gizmo position.
                    //Logger.print(this, "IN ELSE");
                    //If IMobileSpatialObject2D:
                    if(comp != null && usesPositionProperty)
                    {           
                        position = comp.position;
                        rotation = comp.rotation;
                    }
                    //Else, use DisplayObjectRenderer settings, as probably no Spatial component:
                    else
                    {
                        position = target.position;
                        rotation = target.rotation;
                    }                 
                }
            }
            
            //Update last mouse position to current:
            lastMousePos = currentMousePosition.clone();
		}
		
        
		protected override function onAdd():void
		{
			super.onAdd();

            registrationPoint = new Point(0, 0);
			
			PBE.processManager.addTickedObject(this);
			
			scene = PBE.scene;
			position = new Point(00, 200);
			graphics = (displayObject as Sprite).graphics;
     
            zIndex = 65000;
            
            (displayObject as Sprite).addChild(moveGizmo);
            (displayObject as Sprite).addChild(rotateGizmo);
            (displayObject as Sprite).addChild(scaleGizmo);
			
            //moveGizmo.addEventListener(MouseEvent.MOUSE_UP, OnMouseUp); //needed? got stage anyway...
            moveGizmo.addEventListener(MouseEvent.MOUSE_DOWN, OnTranslateGizmoMouseDown);
            moveGizmo.addEventListener(MouseEvent.MOUSE_OVER, OnGizmoMouseOver);
            moveGizmo.addEventListener(MouseEvent.MOUSE_OUT, OnGizmoMouseOut);

            rotateGizmo.addEventListener(MouseEvent.MOUSE_DOWN, OnRotateGizmoMouseDown);
            rotateGizmo.addEventListener(MouseEvent.MOUSE_OVER, OnGizmoMouseOver);
            rotateGizmo.addEventListener(MouseEvent.MOUSE_OUT, OnGizmoMouseOut);

            scaleGizmo.addEventListener(MouseEvent.MOUSE_DOWN, OnScaleGizmoMouseDown);
            scaleGizmo.addEventListener(MouseEvent.MOUSE_OVER, OnGizmoMouseOver);
            scaleGizmo.addEventListener(MouseEvent.MOUSE_OUT, OnGizmoMouseOut);
            
            PBE.mainStage.addEventListener(SelectionChangedEvent.SELECTION_CHANGED, OnSelectionChanged);
            //PBE.mainStage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
            PBE.mainStage.addEventListener(MouseEvent.MOUSE_UP, OnMouseUp); 
			//PBE.mainStage.addEventListener(MouseEvent.CLICK, OnClick);
		}

        
        private function OnSelectionChanged(e:SelectionChangedEvent):void
        {
            //Logger.print(this, "OnSelectionChanged");

            if ( e.selectedEntities.length > 0 )
            {
                targets = new Array();
                for each(var ent:IEntity in e.selectedEntities)
                {
                    var dor:DisplayObjectRenderer = ent.lookupComponentByType(DisplayObjectRenderer) as DisplayObjectRenderer;
                    
                    if (dor != null)
                    {
                        targets.push(dor);
                    }
                }
                
                //var ent:IEntity = e.selectedEntities[0] as IEntity;
                //if(ent)
                //{
                    //target = ent.lookupComponentByType(DisplayObjectRenderer) as DisplayObjectRenderer;
                //}
            }
            else
            {
                targets = null;
            }
        }        
        

        private function OnGizmoMouseOut(e:MouseEvent):void
        {
            //Logger.print(this, "OnGizmoMouseOut");
            EditorMain.isInTransformationMode = false;
        }
        
        private function OnGizmoMouseOver(e:MouseEvent):void
        {
            //Logger.print(this, "OnGizmoMouseOver");
            EditorMain.isInTransformationMode = true;
        }
        
        private function OnTranslateGizmoMouseDown(e:MouseEvent):void
        {
            //Logger.print(this, "OnTranslateGizmoMouseDown");
            isTranslating = true;
        }
        
        private function OnRotateGizmoMouseDown(e:MouseEvent):void
        {
            //Logger.print(this, "OnRotateGizmoMouseDown");
            isRotating = true;
        }        
		
        private function OnScaleGizmoMouseDown(e:MouseEvent):void
        {
            //Logger.print(this, "OnRotateGizmoMouseDown");
            isScaling = true;
        } 
        
        private function OnMouseUp(e:MouseEvent):void
        {
            isTranslating = false;
            isRotating = false;
            isScaling = false;
        }

		protected override function onRemove():void
		{
			//owner.eventDispatcher.removeEventListener(MouseEvent.CLICK, OnClick );
			PBE.processManager.removeTickedObject(this);
		}
		
        
        private var lastMousePos:Point;
        private var isTranslating:Boolean = false;
        private var isRotating:Boolean = false;
        private var isScaling:Boolean = false;
        
        private var moveGizmo:DisplayObject = new Sprite();
        private var rotateGizmo:DisplayObject = new Sprite();
        private var scaleGizmo:DisplayObject = new Sprite();
        
		private var graphics:Graphics = null;
        //private var target:DisplayObjectRenderer = null;
        private var targets:Array = null;
		
		private var handleSize:int = 6;

		private var width:int = 64;
		private var height:int = 64;
		

	}
}